package IC.lir.instructions;
import IC.lir.operands.Operand;
import IC.lir.operands.RegOperand;
import IC.lir.*;


/**
 * A basic instruction that includes the following instructions:
 * 
 * Move instruction:
 *  Op1: Imm, Reg, Mem
 *  Op2: Reg
 * 
 * Move Op1,Op2
 * 
 * *****
 * Arithmetic instructions
 * *****
 * 
 * The Following instructions are Binary Arithmetic instructions 
 * which use the following Operands:
 * 	Op1: Imm, Reg, Mem
 * 	Op2: Reg
 * 
 * Add Op1,Op2
 * Sub Op1,Op2
 * Mul Op1,Op2
 * Div Op1,Op2
 * Mod Op1,Op2
 * 
 * Unary Arithmetic instructions:
 * 	Op1: Reg
 * 
 * Inc Op1
 * Dec Op1
 * Neg Op1
 * 
 * 
 * *****
 *  Logical instructions
 * *****
 * 
 * The Following instructions are Binary Logical instructions 
 * which use the following Operands:
 * 	Op1: Imm, Reg, Mem
 * 	Op2: Reg
 * 
 * And Op1,Op2
 * Or Op1,Op2
 * Xor Op1,Op2
 * Compare Op1,Op2
 * 
 * Unary Logical instructions:
 * 	Op1: Reg
 * 
 * Not Op1
 *
 */
public class BasicInstr extends Instruction {

	private Operand source;
	private RegOperand dest;

	/** instruction kind */
	private Ops op;

	/** enum of possible operations of the instruction */
	public enum Ops {
		// binary arithmtic
		Add,
		Mul,
		Sub,
		Div,
		Mod,

		// unary arithmetic
		Neg,
		Inc,
		Dec,

		// logical
		Not,
		Or,
		And,
		Xor,
		Compare;
		
		public String toString() {
			if (this.equals(Ops.Compare))
				return super.toString();
			else
				return super.toString()+"  ";
		}
	}

	/**
	 * @param source the source operand
	 * @param dest the destination operand
	 * @param op instrcution kind
	 */
	public BasicInstr(Ops op, Operand source, RegOperand dest) {
		this.op = op;
		this.source = source;
		this.dest = dest;
	}

	/**
	 * @param source the source operand
	 * @param dest the destination operand
	 * @param op instrcution kind
	 */
	public BasicInstr(Ops op, RegOperand dest) {
		this.op = op;
		this.source = null;
		this.dest = dest;
	}

	/**
	 * @return the op
	 */
	public Ops getOp() {
		return op;
	}

	/**
	 * @return the dest
	 */
	public RegOperand getDest() {
		return dest;
	}

	/**
	 * @return the source
	 */
	public Operand getSource() {
		return source;
	}

	@Override
	public <D,U> U accept(Visitor<D,U> v, D context) {
		return v.visit(this,context);
	}
}
